package cn.wh.db.router;

import cn.wh.db.router.annotation.DBRouter;
import cn.wh.db.router.strategy.DBRoutingContext;
import cn.wh.db.router.strategy.IDBRoutingStrategy;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @Author wh
 * @Description 数据路由切面 通过自定义路由注解 拦截 增强方法 进行数据库路由 并 释放 threadLocal内存 防止内存溢出
 * @Date 2023/3/28 13:57
 * @Version 1.0
 **/
@Aspect
public class DBRoutingJoinPoint  {
    private Logger logger = LoggerFactory.getLogger(DBRoutingJoinPoint.class);

    private DBRoutingConfig dbRouterConfig;

    private IDBRoutingStrategy dbRouterStrategy;

    public DBRoutingJoinPoint(DBRoutingConfig dbRouterConfig) {
        this.dbRouterConfig = dbRouterConfig;
    }


    @Pointcut("@annotation(cn.wh.db.router.annotation.DBRouter)")
    public void aopPoint() {
    }


    @Around("aopPoint() && @annotation(dbRouter)")
    public Object doRouter(ProceedingJoinPoint jp, DBRouter dbRouter) throws Throwable {
        //获取需要根据的字段路由
        String dbKey = dbRouter.key();

        dbKey = StringUtils.isNotBlank(dbKey) ? dbKey : dbRouterConfig.getRoutingKey();

        //路由字段 不可为空
        if (StringUtils.isBlank(dbKey) && StringUtils.isBlank(dbRouterConfig.getRoutingKey())) {
            throw new RuntimeException("annotation DBRouter key is null！");
        }
        // 路由属性
        String dbKeyAttr = getAttrValue(dbKey, jp.getArgs());

        //获取注解的路由策略值
        String routingStrategy = dbRouter.routingStrategy();

        //获取具体策略值
        if (StringUtils.isBlank(routingStrategy)) {
            dbRouterStrategy = DBRoutingContext.getDBRoutingStrategy(dbRouterConfig);
        } else {
            dbRouterStrategy = DBRoutingContext.getDBRoutingStrategy(dbRouterConfig, routingStrategy);
        }
        // 走路由
        dbRouterStrategy.doRouter(dbKeyAttr);
        try {
            return jp.proceed();
        } finally {
            //释放内存 防止 内存泄露
            dbRouterStrategy.clear();
        }
    }


    /**
     * 获取 路由字段的值
     *
     * @param attr 路由字段
     * @param args 参数
     * @return
     */
    public String getAttrValue(String attr, Object[] args) {
        if (1 == args.length) {
            Object arg = args[0];
            if (arg instanceof String) {
                return arg.toString();
            }
        }

        String filedValue = null;
        for (Object arg : args) {
            try {
                if (StringUtils.isNotBlank(filedValue)) {
                    break;
                }
                filedValue = BeanUtils.getProperty(arg, attr);
            } catch (Exception e) {
                logger.error("获取路由属性值失败 attr：{}", attr, e);
            }
        }
        return filedValue;
    }

}
